use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, Row, sqlite::SqliteRow};
use std::str::FromStr;

/// 股票K线数据结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StockCandle {
    /// 股票代码
    pub symbol: String,
    
    /// 时间周期 (1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w, 1M)
    pub period: String,
    
    /// 开盘时间
    pub timestamp: DateTime<Utc>,
    
    /// 开盘价
    pub open: Decimal,
    
    /// 最高价
    pub high: Decimal,
    
    /// 最低价
    pub low: Decimal,
    
    /// 收盘价
    pub close: Decimal,
    
    /// 成交量
    pub volume: Decimal,
    
    /// 成交额
    pub amount: Option<Decimal>,
    
    /// 涨跌幅
    pub change_percent: Option<Decimal>,
    
    /// 换手率
    pub turnover_rate: Option<Decimal>,
    
    /// 是否为交易日
    pub is_trading_day: bool,
    
    /// 数据来源
    pub source: Option<String>,
    
    /// 创建时间
    pub created_at: Option<DateTime<Utc>>,
    
    /// 更新时间
    pub updated_at: Option<DateTime<Utc>>,
}

impl FromRow<'_, SqliteRow> for StockCandle {
    fn from_row(row: &SqliteRow) -> Result<Self, sqlx::Error> {
        Ok(StockCandle {
            symbol: row.try_get("symbol")?,
            period: row.try_get("period")?,
            timestamp: row.try_get("timestamp")?,
            open: Decimal::from_str(&row.try_get::<String, _>("open")?).unwrap_or_default(),
            high: Decimal::from_str(&row.try_get::<String, _>("high")?).unwrap_or_default(),
            low: Decimal::from_str(&row.try_get::<String, _>("low")?).unwrap_or_default(),
            close: Decimal::from_str(&row.try_get::<String, _>("close")?).unwrap_or_default(),
            volume: Decimal::from_str(&row.try_get::<String, _>("volume")?).unwrap_or_default(),
            amount: row.try_get::<Option<String>, _>("amount")?.map(|s| Decimal::from_str(&s).unwrap_or_default()),
            change_percent: row.try_get::<Option<String>, _>("change_percent")?.map(|s| Decimal::from_str(&s).unwrap_or_default()),
            turnover_rate: row.try_get::<Option<String>, _>("turnover_rate")?.map(|s| Decimal::from_str(&s).unwrap_or_default()),
            is_trading_day: row.try_get("is_trading_day")?,
            source: row.try_get("source")?,
            created_at: row.try_get("created_at")?,
            updated_at: row.try_get("updated_at")?,
        })
    }
}

impl StockCandle {
    /// 创建新的股票K线数据
    pub fn new(
        symbol: String,
        period: String,
        timestamp: DateTime<Utc>,
        open: Decimal,
        high: Decimal,
        low: Decimal,
        close: Decimal,
        volume: Decimal,
    ) -> Self {
        Self {
            symbol,
            period,
            timestamp,
            open,
            high,
            low,
            close,
            volume,
            amount: None,
            change_percent: None,
            turnover_rate: None,
            is_trading_day: true,
            source: None,
            created_at: Some(Utc::now()),
            updated_at: Some(Utc::now()),
        }
    }
    
    /// 计算涨跌幅
    pub fn calculate_change_percent(&mut self, previous_close: Decimal) -> Decimal {
        if previous_close.is_zero() {
            return Decimal::ZERO;
        }
        
        let change = (self.close - previous_close) / previous_close * Decimal::new(100, 0);
        self.change_percent = Some(change);
        change
    }
    
    /// 检查是否是上涨K线
    pub fn is_bullish(&self) -> bool {
        self.close > self.open
    }
    
    /// 检查是否是下跌K线
    pub fn is_bearish(&self) -> bool {
        self.close < self.open
    }
    
    /// 检查是否是十字星K线
    pub fn is_doji(&self) -> bool {
        // 开盘价和收盘价非常接近，上下影线较长
        let body_size = (self.close - self.open).abs();
        let total_range = self.high - self.low;
        
        if total_range.is_zero() {
            return false;
        }
        
        // 实体占总长度的比例小于20%可视为十字星
        (body_size / total_range) < Decimal::new(20, 2)
    }
    
    /// 计算实体部分的大小
    pub fn body_size(&self) -> Decimal {
        (self.close - self.open).abs()
    }
    
    /// 计算上影线长度
    pub fn upper_shadow(&self) -> Decimal {
        if self.is_bullish() {
            self.high - self.close
        } else {
            self.high - self.open
        }
    }
    
    /// 计算下影线长度
    pub fn lower_shadow(&self) -> Decimal {
        if self.is_bullish() {
            self.open - self.low
        } else {
            self.close - self.low
        }
    }
    
    /// 转换为JSON字符串
    pub fn to_json(&self) -> Result<String, serde_json::Error> {
        serde_json::to_string(self)
    }
}